#ifndef _HASH_H_
#define _HASH_H_

#include <stdbool.h>
#include <stdint.h>
#include <sys/types.h>
#include <string.h>
#include <ctype.h>

struct z_rstring
{
  char *string;
  uint32_t size;
};

typedef struct z_rstring z_rstring;

typedef uint32_t z_hash_func(const void *key);
typedef bool z_equal_func(const void *key1, const void *key2);
typedef void z_hfunc(void *key, void *value, void *user_data);
typedef void z_destroy_notify (void *data);

z_hash_func z_rstring_hash;
z_equal_func z_rstring_equal;

typedef struct z_hash_table z_hash_table;

/* Create a new z_hash_table.
 * @param hash_func a function to create a hash value from a key
 * @param key_equal_func a function to check two keys for equality.
 * @return a new z_hash_table.
 */
z_hash_table* z_hash_table_new(z_hash_func hash_func, z_equal_func key_equal_func);


/* Creates a new z_hash_table like z_hash_table_new and allows to specify
 * functions to free the memory allocate for the key and value that get
 * called when removing the entry from the z_hash_table
 * @param hash_func a function to create a hash value from a key
 * @param key_equal_func a functino to check two keys for equality
 * @param key_destroy_func a function to destroy the key
 * @param value_destroy_func a function to destroy the value
 * @return a new z_hash_table.
 */
z_hash_table* z_hash_table_new_full(z_hash_func hash_func, z_equal_func key_equal_func,
                                    z_destroy_notify key_destroy_func, 
                                    z_destroy_notify value_destroy_func);

/* Destroy the z_hash_table. If keys and/or values are dynamically
 * allocated, you should either free thm first or create the z_hash_table
 * @param hash_table a z_hash_table.
 */
void z_hash_table_destory(z_hash_table *hash_table);

/* Insert a new key and value into a z_hash_table.
 * If the key already exits in the table, replace value!
 * @param hash_table a z_hash_table
 * @param key a key to insert.
 * @param value the value to associate with the key
 */
void z_hash_table_insert(z_hash_table *hash_table, void *key, void *value);

/* Looks up a key in a z_hash_table.
 * @param hash_table in a z_hash_table
 * @param key the key to look up
 * @return the associated value. NULL if no exits
 */
void *z_hash_table_look_up(z_hash_table *hash_table, const void *key);

/* Calls the given function for each key/value pairs in the table.
 * @post the hash table may not be modify while iterating over
 * @param hash_table a hash_table.
 * @param func the function to call for each key/value pair.
 * @param usre_data to pass to the function
 */
void z_hash_table_foreach(z_hash_table *hash_table, z_hfunc *func, void *user_data);

/* Returns the number of elements contained in the z_hash_table.
 * @param hash_table a z_hash_table
 * @return the number of key/value pairs.
 */
uint32_t z_hash_table_size(z_hash_table *hash_table);

/* string hash functin */
uint32_t z_rstring_hash(const void *key);
bool z_rstring_equal(const void *key1, const void *key2);

#endif /* _HASH_H_ */
